/**************************************************************************************************
*  Project:
*  Platform:			MPC5744P
*  Filename:			PCA21125.c
*  Author:
*  Version: 			1.0.0
*  Date: 				26/06/2017
*  Description: 
*  Revision:
* 
*  (c) Copyright
*  All Rights Reserved.
***************************************************************************************************/
/*
 
*/

/*******************************************************************************
**                                 include                                    **
*******************************************************************************/
#include "PCA21125.h"
#include "spi.h"
#include "APP_BSW.h"
//#include "Spi_Cfg.h"
//#include "Dio.h"
//#include "Dio_Cfg.h"
//#include "ABI.h"
//#include "DEM_Types.h"
//#include "DEM_Cfg.h"
//#include "ABI_OSEK.h"
//#include "NvM.h"
//#include "Fls.h"
//#include "Fee.h"
//#include "IO_Abstraction.h"
//#include "ModelIO.h"

/*******************************************************************************
**                                 Local Variables                            **
*******************************************************************************/
static uint16 PCA21125_TxBuffer[PCA21125_SPIMAX_EBBUFF] = {0};
static uint16 PCA21125_RxBuffer[PCA21125_SPIMAX_EBBUFF] = {0};

/*==================================================================================================
                                        Global Variables
==================================================================================================*/     
#define RTC_FrequencyRegister 000 //32768HZ

//#define NVM_REQ_PENDING 2u

uint8  NvMBlockTime_RAM[7]={0x18,0x01,0x00,0x01,0x12,0x01,0x00};

uint8 PCA21125_Init_Step = INIT_En;
uint8 PCA21125_Settime_Step = Set_Timer_Step;
uint8 PCA21125_InitErr = 0;
uint8 Set_TimerStep_ErrNum = 0;
uint8 PCA21125_Initcorrect_flg = 0;
uint8 PCA21125_Setting_Timer_flg = 0;
uint8 time = 0; 

PCA21125_Regs PCA21125_regs; 
PCA21125_Regs PCA_Register;
BCD_Time BCD_time;
//ABI_RTCType RTC_time = {0};
ABI_RTCTime_Type RTC_time_vaule;

uint16 RTC_timercount = 0;

uint8 BMSKl30Off_Flg = 0;

/*==================================================================================================
                              Local Functions
==================================================================================================*/
static Std_ReturnType PCA21125_SpiSequenceReq(uint8 *send_data, uint8 *rx_data, uint8 data_bytes, uint32 spi_periph)
{
    uint8 Ret = E_OK;
    uint32 i = 0;
    Spi_SeqResultType Result = SPI_SEQ_FAILED;

    if(data_bytes > PCA21125_SPIMAX_EBBUFF)
    {
        return E_NOT_OK;
    }

    for(i = 0; i < data_bytes; i++)
    {
        PCA21125_TxBuffer[i] = (uint16) send_data[i];
        PCA21125_RxBuffer[i] = (uint16) rx_data[i];
    }

    Ret = Spi_SetupEB(spi_periph, PCA21125_TxBuffer, PCA21125_RxBuffer, data_bytes);

    if(E_NOT_OK == Ret)
    {
        return E_NOT_OK;
    }

   // Ret = Spi_SyncTransmit(spi_periph);
   /* if(E_NOT_OK == Ret)
    {
        return E_NOT_OK;
    }*/

    for(i = 0; i < PCA21125_SPIMAX_DELAY_TIME; i++)
    {
        Result = Spi_GetSequenceResult(spi_periph);
        if(SPI_SEQ_OK == Result) 
        {
            break;
        }
    }
    if(i >= PCA21125_SPIMAX_DELAY_TIME) 
    {
        Ret = E_NOT_OK;
    }

    for(i = 0; i < data_bytes; i++)
    {
        rx_data[i] = (uint8) PCA21125_RxBuffer[i];
    }

    return Ret;
}

static uint8 PCA21125_ReadSeconds(pBCD_Time data) //get register value from 02h to 08h 
{
    uint8 Rx_Data[8] = {0};
    uint8 spi_data[8] = {0};
    uint8 Ret = E_NOT_OK;
    uint8 i, j;
    uint8 Count = 5;

    spi_data[0] = (read_command << 4) | Seconds_register_address;
    for (j = 1; j < 8; j++)
    {
        spi_data[j] = 0x00;
    }
    for (i = 0; i < 8; i++)
    {
        Rx_Data[i] = 0x00;
    }

    do
    {
        Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 8, SPI0);
        if(E_OK == Ret)
        {
            break;
        }
    }
    while(--Count);

    if(0 == Count)
    {
        Ret = E_NOT_OK;
    }


    data->Seconds.R = Rx_Data[1];
    data->Minutes.R = Rx_Data[2];
    data->Hours_24.R = Rx_Data[3];
    data->Days.R = Rx_Data[4];
    data->Weekdays.R = Rx_Data[5];
    data->Months.R = Rx_Data[6];
    data->Years.R = Rx_Data[7];   

    return Ret; 
}

static uint8 PCA21125_ReadControls(pPCA21125_Regs data) //get register value from 00h to 01h 
{
    uint8 Rx_Data[3] = {0};
    uint8 spi_data[3] = {0};
    uint8 Ret = E_NOT_OK;
    uint8 i,j;
    uint8 Count = 5;

    spi_data[0] = (read_command << 4) | Control1_register_address;
    for (j = 1; j < 3; j++)
    {
        spi_data[j] = 0x00;
    }
    for (i = 0; i < 3; i++)
    {
        Rx_Data[i] = 0x00;
    }

    do
    {
        Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 3, SPI0);
        if(E_OK == Ret)
        {
            break;
        }
    }
    while(--Count);

    if(0 == Count)
    {
        Ret = E_NOT_OK;
    }

    data->Control_1.R = Rx_Data[1];
    data->Control_2.R = Rx_Data[2];

    return Ret; 
}


/*==================================================================================================
                                       GLOBAL FUNCTIONS
==================================================================================================*/
uint8 PCA21125_Write_Inittime(uint8 init_year, uint8 init_month, uint8 init_weekdays,
	uint8 init_days, uint8 init_hours, uint8 init_mins, uint8 init_seconds) 
{
    uint8 Rx_Data[16] = {0};
    uint8 spi_data[16];
    uint8 Ret = E_NOT_OK;
    uint8 Init_year = 0;
    uint8 Init_month = 0;
    uint8 Init_weekdays = 0;
    uint8 Init_days = 0;
    uint8 Init_hours = 0;
    uint8 Init_mins = 0;
    uint8 Init_seconds = 0;

    if(init_year < 100)
        Init_year = DecToBCD(init_year);
    else
        Init_year = 0;

    if(init_month < 13)
        Init_month = DecToBCD(init_month);
    else
        Init_month = 1;

    if(init_weekdays < 13)
        Init_weekdays = DecToBCD(init_weekdays);
    else
        Init_weekdays = 1;

    if(init_days < 32)
        Init_days = DecToBCD(init_days);
    else 
        Init_days = 1;

    if(init_hours < 24)
        Init_hours = DecToBCD(init_hours);
    else
        Init_hours = 0;
    
    if(init_mins < 60)   
        Init_mins = DecToBCD(init_mins);
    else
        Init_mins = 0;

    if(init_seconds < 60)
        Init_seconds = DecToBCD(init_seconds);
    else
        Init_seconds = 0;
        
    spi_data[0] = 0x10; // R/W is write , begining address is 00h write pca21125 SDI
    spi_data[1] = 0x00; //control/status 1, no test modes or POR override 24 hour mode selected
    spi_data[2] = 0x00; //control/status 2, no alarm/timer flags or interrupts
    spi_data[3] = Init_seconds;//0x00; //set seconds, clear voltage low detector
    spi_data[4] = Init_mins;//0x00; //set minutes to 0
    spi_data[5] = Init_hours;//0x12; //set hours to 12
    spi_data[6] = Init_days;//0x01; //set days to 1
    spi_data[7] = Init_weekdays;//0x01; //set weekdays to Monday , Monday is day 1
    spi_data[8] = Init_month;//0x01; //set month to 1 
    spi_data[9] = Init_year;//0x18; //set years to 18
    spi_data[10] = 0x80; //disable minute alarm and reset to 00
    spi_data[11] = 0x80; //disable hour alarm and reset to 00
    spi_data[12] = 0x80; //disable day alarm and reset to 00
    spi_data[13] = 0x80; //disable weekday alarm and reset to 00
    spi_data[14] = 0x00; //set frequency out to 32768 Hz e.g. for tuning
    spi_data[15] = 0x00; //timer switched off

    Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 16, SPI0);

    return Ret;
}

//Initialization of the RTC and setting the time
void PCA21125_Init(void)
{
	uint8 ret = E_OK;

    while(PCA21125_Initcorrect_flg == 0)
    {				
        ret = PCA21125_Write_Inittime(18, 1, 1, 1, 12, 0, 0);//the time to be set is Monday, January first 2018 12:00:00 (24 hours)
        if (ret == E_OK)
        {
            PCA21125_Initcorrect_flg = 1;
        }
        else
        {
            PCA21125_Initcorrect_flg = 0;	
            PCA21125_InitErr++;
        }
        		
        if(PCA21125_InitErr_Num > PCA21125_MAX_INITERR_NUM)
        {
            PCA21125_Initcorrect_flg = 0;					  
            PCA21125_InitErr = 0;
            break; //exit while  
        }
    }
   
}

uint8 PCA21125_Settime(uint32_t timevalue) 
{ 
    uint8 Rx_Data[8] = {0};
    uint8 spi_data[8];
    uint8 Ret = E_NOT_OK;
    uint8 Init_year, Init_month, Init_weekdays, Init_days, Init_hours, Init_mins, Init_seconds;
    ABI_RTCTime_Type ss;

    ss.R = timevalue;
    if(ss.B.year < 100)
        Init_year = DecToBCD(ss.B.year);
    else
        Init_year = 0;

    if(ss.B.month < 13)
        Init_month = DecToBCD(ss.B.month);
    else
        Init_month = 1;

    Init_weekdays = DecToBCD(0);

    if(ss.B.day < 32)
        Init_days = DecToBCD(ss.B.day);
    else 
        Init_days = 1;

    if(ss.B.hour < 24)
        Init_hours = DecToBCD(ss.B.hour);
    else
        Init_hours = 0;
    
    if(ss.B.minute < 60)   
        Init_mins = DecToBCD(ss.B.minute);
    else
        Init_mins = 0;

    /*if(ss.B.second < 60)
        Init_seconds = DecToBCD(ss.B.second);
    else
        Init_seconds = 0;*/
        
    Init_seconds = DecToBCD(0);

    spi_data[0] = 0x12; // R/W is write , begining address is 02h write pca21125 SDI
    spi_data[1] = Init_seconds;//0x00; //set seconds, clear voltage low detector
    spi_data[2] = Init_mins;//0x00; //set minutes to 0
    spi_data[3] = Init_hours;//0x12; //set hours to 12
    spi_data[4] = Init_days;//0x01; //set days to 1
    spi_data[5] = Init_weekdays;//0x01; //set weekdays to Monday , Monday is day 1,sunday is day 0
    spi_data[6] = Init_month;//0x01; //set month to 1 
    spi_data[7] = Init_year;//0x18; //set years to 18

    Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 8, SPI0);

    return Ret;
}

uint8 PCA21125_ClearRF(void) 
{
	 uint8 Rx_Data[16] = {0};
	 uint8 spi_data[16];
	 uint8 Ret = E_OK;
	 
	 if(RTC_time.resetflag == 1)
	 {
		 spi_data[0] = 0x12; // R/W is write , begining address is 03h write pca21125 seconds
		 spi_data[1] = 0x00;//0x00; //set seconds, clear voltage low detector
		 Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 2, SPI0);
	 }
	 return Ret;
}

uint8 PCA21125_ClearAF(void)
{
	 uint8 Rx_Data[2] = {0};
	 uint8 spi_data[2];
	 uint8 Ret = E_OK;
	 
	 Ret = PCA21125_ReadControls(&PCA21125_regs);
	  PCA_Register.Control_2.R = PCA21125_regs.Control_2.R;
	  if((PCA_Register.Control_2.B.AF)== 1)
	  {
	  	spi_data[0] = (write_command << 4)| Control2_register_address;
	    spi_data[1] = 0x00;
		
		Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 2, SPI0);
		
	  }
	return Ret;
}

uint8 PCA21125_ClearTF(void)
{
	 uint8 Rx_Data[2] = {0};
	 uint8 spi_data[2];
	 uint8 Ret = E_OK;
	 
	 Ret = PCA21125_ReadControls(&PCA21125_regs);
	  PCA_Register.Control_2.R = PCA21125_regs.Control_2.R;
	  if((PCA_Register.Control_2.B.TF)== 1)
	  {
	  	spi_data[0] = (write_command << 4)| Control2_register_address;
	    spi_data[1] = 0x00;
		
		Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 2, SPI0);
		
	  }
	return Ret;
}


uint8 PCA21125_EnableAlarm(void)
{
	uint8 Rx_Data[2] = {0};
	uint8 spi_data[2] = {0};
	uint8 Ret = E_NOT_OK;

    spi_data[0] = (write_command << 4)| Control2_register_address;
    spi_data[1] = 0x02;
	
	Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 2, SPI0);
	return Ret;
}

uint8 PCA21125_SetAlarm(uint8 min_data, uint8 hour_data, uint8 day_data, uint8 weekday_data,
uint8 ae_m, uint8 ae_h, uint8 ae_d, uint8 ae_w) 
{
	  uint8 Rx_Data[5] = {0};
	  uint8 spi_data[5] = {0};
	  uint8 Ret = E_NOT_OK;
	  uint8 Min_data = DecToBCD(min_data);
	  uint8 Hour_data = DecToBCD(hour_data);
	  uint8 Day_data = DecToBCD(day_data);
	  uint8 Weekday_data = DecToBCD(weekday_data);
	  
	  spi_data[0] = 0x10 | Min_alarm_address;
	  spi_data[1] = (ae_m<< 7) | Min_data;
	  spi_data[2] = (ae_h<< 7) | Hour_data;
	  spi_data[3] = (ae_d<< 7) | Day_data;
	  spi_data[4] = (ae_w<< 7) | Weekday_data;
	  
	  Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 5, SPI0);
	  PCA21125_EnableAlarm();

	  return Ret;
}

uint8 PCA21125_Countdown(uint32 minute)
{
    //in this example clock to be used is 1Hz ,generates an 1 min interrupt
	uint8 Ret = E_NOT_OK;
	uint8 Rx_Data[2] = {0};
	uint8 spi_data[2] = {0};

	//contorl/status register 2, enable countdown interrupt
	spi_data[0] = 0x11;
	spi_data[1] = 0x11;
	Rx_Data[0] = 0xff;
	Rx_Data[1] = 0xff;				
	Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 2, SPI0);

	if (Ret == 0)
	{
		//register address 0Fh ,Timer value set to 60, 3cHEX 
		spi_data[0] = 0x1f;
		if(minute < 256)
		{ 
			spi_data[1] = minute;
		}
		else
		{
		    return E_NOT_OK;
		}
		Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 2, SPI0);
        	
		if (Ret == 0)
		{
			//register address 0Eh ,clock selected 1Hz
			spi_data[0] = 0x1e;//command and address
			spi_data[1] = 0x82;//enable timer and select frequency 1/60Hz
			Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 2, SPI0);	
			if (Ret == 0)
			{
				Ret = E_OK;
			}
			else
			{
				Ret = E_NOT_OK;
			}
		}
		else
		{
			Ret = E_NOT_OK;
		}
	}
	else
	{
		Ret = E_NOT_OK;
	}
		
	return Ret;
}

uint8 PCA21125_DisableCountdown(void)
{
	uint8 Ret = E_NOT_OK;
	uint8 Rx_Data[2] = {0};
	uint8 spi_data[2] = {0};

	//contorl/status register 2, disable countdown interrupt
	spi_data[0] = 0x1e;//command and address
	spi_data[1] = 0x00;//disable timer and select frequency 1/60Hz			
	Ret = PCA21125_SpiSequenceReq(spi_data, Rx_Data, 2, SPI0);
		
	return Ret;
}

uint8 PCA21125_ReadTime(void)
{
	uint8 Ret = E_NOT_OK;

	Ret = PCA21125_ReadSeconds(&BCD_time);
	Ret |= PCA21125_ReadControls(&PCA21125_regs);
	RTC_time.countdownflag = PCA21125_regs.Control_2.B.TF;
	//RTC_time.resetflag = BCD_time.Seconds.B.RF;
	
	RTC_time.second = BCD_time.Seconds.B.TEN * 10 + BCD_time.Seconds.B.UINT; 
	RTC_time.minute = BCD_time.Minutes.B.TEN * 10 + BCD_time.Minutes.B.UINT; 
	RTC_time.hour = BCD_time.Hours_24.B.TEN * 10 + BCD_time.Hours_24.B.UINT; 
	RTC_time.day = BCD_time.Days.B.TEN * 10 + BCD_time.Days.B.UINT; 
	RTC_time.weekday = BCD_time.Weekdays.B.WEEKDAYS; 
	RTC_time.month = BCD_time.Months.B.TEN * 10 + BCD_time.Months.B.UINT;
	RTC_time.year = BCD_time.Years.B.TEN * 10 + BCD_time.Years.B.UINT; 
	
    RTC_time_vaule.B.year = RTC_time.year; 
    RTC_time_vaule.B.month = RTC_time.month;
    RTC_time_vaule.B.day = RTC_time.day;
    RTC_time_vaule.B.hour = RTC_time.hour;
    RTC_time_vaule.B.minute = RTC_time.minute;
    
	return Ret;
}


void BCDtoDecimal(pBCD_Time bcd , pTime p)
{
	p->Seconds = bcd->Seconds.B.TEN * 10 + bcd->Seconds.B.UINT;
	p->Minutes = bcd->Minutes.B.TEN * 10 + bcd->Minutes.B.UINT;
	p->Hours = bcd->Hours_24.B.TEN * 10 + bcd->Hours_24.B.UINT;
	p->Days = bcd->Days.B.TEN * 10 + bcd->Days.B.UINT;
	p->Weekdays = bcd->Weekdays.B.WEEKDAYS;
	p->Months = bcd->Months.B.TEN * 10 + bcd->Months.B.UINT;
	p->Years = bcd->Years.B.TEN * 10 + bcd->Years.B.UINT;
}

unsigned char DecToBCD(unsigned char dec)
{
	return ((dec / 10) << 4) | (dec % 10);
}

void RTC_Management(void)
{
   // uint8 NvMResult = NVM_REQ_PENDING;
    
    if(RTC_timercount == 1)
    {
        RTC_timercount = 0;
        
        PCA21125_ReadTime();
        if(BCD_time.Seconds.B.RF == 1)
        {
            RTC_time.resetflag = 1;
            
            PCA21125_Write_Inittime(NvMBlockTime_RAM[0], NvMBlockTime_RAM[1], NvMBlockTime_RAM[2], \
            NvMBlockTime_RAM[3], NvMBlockTime_RAM[4], NvMBlockTime_RAM[5], NvMBlockTime_RAM[6]);

            RTC_time_vaule.B.year = NvMBlockTime_RAM[0]; 
            RTC_time_vaule.B.month = NvMBlockTime_RAM[1];
            RTC_time_vaule.B.day = NvMBlockTime_RAM[3];
            RTC_time_vaule.B.hour = NvMBlockTime_RAM[4];
            RTC_time_vaule.B.minute = NvMBlockTime_RAM[5];
            RTC_time.year = RTC_time_vaule.B.year; 
            RTC_time.month = RTC_time_vaule.B.month;
            RTC_time.day = RTC_time_vaule.B.day;
            RTC_time.hour = RTC_time_vaule.B.hour;
            RTC_time.minute = RTC_time_vaule.B.minute; 

            BMSKl30Off_Flg = 1;
        }
        else
        {}
        
      //  RunR();
        RTC_time.timevalidflag = 1;
    }

    RTC_timercount++;
}




